/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "quakedef.h"
#include "menu.shared.h"

void M_CompletePlayerSetup (void);

class qmenu_setup_t : public qmenu_t
{
private:
	class qmenu_colourbar_t : public qmenu_option_t
	{
	public:
		qmenu_colourbar_t (char *text)
		{
			Q_strncpy (this->Text, text, strlen (this->Text) - 1);
			this->Colour = 0;
			this->Active = TRUE;
		}

		int Draw (int y)
		{
			y += 2;

			// draw text
			M_DrawStringOption (y, this->Text);

			// figure current colour
			int colour = this->Colour;
			int intense = colour * 16 + (colour < 8 ? 11 : 4);

			// colour bar
			for (int i = 0; i < 14; i++)
			{
				// take the approximate midpoint colour (handle backward ranges)
				int c = i * 16 + (i < 8 ? 8 : 7);

				// braw baseline colour (offset downwards a little so that it fits correctly
				Draw_Fill ((vid.Width >> 1) + 16 + i * 8, y + menu_ofsy, 8, 8, c);
			}

			// draw the highlight rectangle
			Draw_Fill ((vid.Width >> 1) + 15 + colour * 8, (y + menu_ofsy) - 1, 10, 10, 15);

			// redraw the highlighted color at brighter intensity (handle backward ranges)
			Draw_Fill ((vid.Width >> 1) + 16 + colour * 8, (y  + menu_ofsy), 8, 8, intense);

			return y + 14;
		}

		void DrawHighlight (int y)
		{
			M_DrawHighlight (y + 2, 320);
		}

		BOOL Key (int key)
		{
			switch (key)
			{
			case K_LEFTARROW: this->Colour--; break;
			case K_RIGHTARROW: this->Colour++; break;
			default: return FALSE;
			}

			if (this->Colour > 13) this->Colour = 0;
			if (this->Colour < 0) this->Colour = 13;

			return TRUE;
		}

		int GetColour (void) {return this->Colour;}
		void SetColour (int colour) {this->Colour = colour;}

	private:
		int Colour;
	};

	// done this way so that we can access it's properties
	qmenu_colourbar_t *SetupTop;
	qmenu_colourbar_t *SetupBottom;

	class qmenu_customdraw_t : public qmenu_option_t
	{
	public:
		qmenu_customdraw_t (void) {this->Active = FALSE;}

		int Draw (int y)
		{
			M_DrawCenteredPic (y - 4, Draw_CachePic ("gfx/bigbox.lmp"));
			M_DrawCenteredPic (y + 4, Draw_CachePic ("gfx/menuplyr.lmp"));
			return y + 64;
		}

		BOOL Key (int key) {return FALSE;}
		void DrawHighlight (int y) {}
	};

public:
	qmenu_setup_t (void)
	{
		// add options to the menu
		this->AddOption (new qmenu_banner_t ("gfx/p_multi.lmp"));
		this->AddOption (new qmenu_divider_t ());

		this->AddOption (new qmenu_textbox_t ("Hostname", this->SetupHostname, 17));
		this->AddOption (new qmenu_textbox_t ("Your name", this->SetupMyName, 17));
		this->AddOption (new qmenu_divider_t ());

		// create our colour bars as class members so that we can access their properties locally
		this->SetupTop = new qmenu_colourbar_t ("Shirt color");
		this->SetupBottom = new qmenu_colourbar_t ("Pants color");

		// now add our colour bars
		this->AddOption (this->SetupTop);
		this->AddOption (this->SetupBottom);

		// add a custom draw object for the translate pic
		this->AddOption (new qmenu_customdraw_t ());
		this->AddOption (new qmenu_divider_t ());

		this->AddOption (new qmenu_action_t ("Accept changes", M_CompletePlayerSetup));

		// and register our menu
		this->Register (m_setup);

		// navigate one back to highlight the "accept changes" option on first entry
		this->Navigate (-1);
	}

	void EnterFunc (void)
	{
		this->EnterMenu ();

		// copy off current settings to our controls
		Q_strncpy (this->SetupMyName, cl_name->string, 16);
		Q_strncpy (this->SetupHostname, hostname->string, 16);

		this->SetupTop->SetColour (cl_color->integer >> 4);
		this->SetupBottom->SetColour (cl_color->integer & 15);

		// for colour change tracking
		this->SetupOldTop = this->SetupTop->GetColour ();
		this->SetupOldBottom = this->SetupBottom->GetColour ();
	}

protected:
	void CustomDraw (void)
	{
		// build a translation table
		this->BuildTranslationTable (this->SetupTop->GetColour () * 16, this->SetupBottom->GetColour () * 16);
	}

private:
	void BuildTranslationTable (int top, int bottom)
	{
		static int old_top = -1;
		static int old_bottom = -1;

		if (top != old_top || bottom != old_bottom)
		{
			byte identityTable[256];
			byte translationTable[256];

			// ensure that the pic is cached
			Draw_CachePic ("gfx/menuplyr.lmp");

			for (int j = 0; j < 256; j++)
				identityTable[j] = j;

			byte *dest = translationTable;
			byte *source = identityTable;
			memcpy (dest, source, 256);

			if (top < 128)	// the artists made some backwards ranges.  sigh.
				memcpy (dest + TOP_RANGE, source + top, 16);
			else
				for (int j = 0; j < 16; j++)
					dest[TOP_RANGE + j] = source[top + 15 - j];

			if (bottom < 128)
				memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
			else
				for (int j = 0; j < 16; j++)
					dest[BOTTOM_RANGE + j] = source[bottom + 15 - j];

			// and translate the pic
			Draw_TranslatePic (Draw_CachePic ("gfx/menuplyr.lmp"), translationTable);
			old_top = top;
			old_bottom = bottom;
		}
	}

public:
	void CompletePlayerSetup (void)
	{
		if (Q_strcmp (cl_name->string, this->SetupMyName) != 0)
			Cbuf_AddText (va ("name \"%s\"\n", this->SetupMyName));

		if (Q_strcmp (hostname->string, this->SetupHostname) != 0)
			Cvar_Set (hostname, this->SetupHostname);

		if (this->SetupTop->GetColour () != this->SetupOldTop || this->SetupBottom->GetColour () != this->SetupOldBottom)
			Cbuf_AddText (va ("color %i %i\n", this->SetupTop->GetColour (), this->SetupBottom->GetColour ()));

		this->LeaveMenu ();
	}

private:
	char SetupHostname[32];
	char SetupMyName[32];
	int SetupOldTop;
	int	SetupOldBottom;
} menu_setup;


void M_CompletePlayerSetup (void)
{
	// done like this because the setup attribs are private
	menu_setup.CompletePlayerSetup ();
}

